package top.lyjwn.todo.weinxin.utils;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.lyjwn.todo.weinxin.param.WXPayParam;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 生成签名
 *
 * @author luoyujie
 */
@Component
public class SignUtil {

    @Autowired
    private WXPayParam wxPayParam;
    /**
     * @param object
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws IllegalStateException
     */
    public  String getSign(Object object) {
        String urlkeyValuePair = getUrlkeyValuePair(object);
        String stringSignTemp = urlkeyValuePair + "&key=" + wxPayParam.getApiKey();
        if (urlkeyValuePair.contains("HMAC-SHA256")) {
            Mac sha256_HMAC = null;
            try {
                sha256_HMAC = Mac.getInstance("HmacSHA256");
                SecretKeySpec secret_key = new SecretKeySpec(wxPayParam.getApiKey().getBytes(), "HmacSHA256");
                sha256_HMAC.init(secret_key);
                // utf-8 : 解决中文加密不一致问题,必须指定编码格式
                return byteArrayToHexString(sha256_HMAC.doFinal(stringSignTemp.getBytes("utf-8"))).toUpperCase();
            } catch (NoSuchAlgorithmException | InvalidKeyException | IllegalStateException
                    | UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            return DigestUtils.md5Hex(stringSignTemp).toUpperCase();
//			return DigestUtils.sha256Hex(stringSignTemp).toUpperCase();
        }
        return null;

    }

    /**
     * @param map
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws IllegalStateException
     */
    public  String getSign(Map<String,Object> map) {
        String urlkeyValuePair = getUrlkeyValuePair(map);
        String stringSignTemp = urlkeyValuePair + "&key=" + wxPayParam.getApiKey();
        if (urlkeyValuePair.contains("HMAC-SHA256")) {
            Mac sha256_HMAC = null;
            try {
                sha256_HMAC = Mac.getInstance("HmacSHA256");
                SecretKeySpec secret_key = new SecretKeySpec(wxPayParam.getApiKey().getBytes(), "HmacSHA256");
                sha256_HMAC.init(secret_key);
                // utf-8 : 解决中文加密不一致问题,必须指定编码格式
                return byteArrayToHexString(sha256_HMAC.doFinal(stringSignTemp.getBytes("utf-8"))).toUpperCase();
            } catch (NoSuchAlgorithmException | InvalidKeyException | IllegalStateException
                    | UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            return DigestUtils.md5Hex(stringSignTemp).toUpperCase();
//			return DigestUtils.sha256Hex(stringSignTemp).toUpperCase();
        }
        return null;

    }

    /**
     * 将加密后的字节数组转换成字符串
     *
     * @param b 字节数组
     * @return 字符串
     */
    private  String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }

    /**
     * url键值对
     *
     * @param object
     * @return
     */
    public  String getUrlkeyValuePair(Object object) {
        String[] filedNames = getFiledNames(object);
        Arrays.sort(filedNames);
        StringBuffer urlKeyValue = new StringBuffer();
        for (String filedName : filedNames) {
            Object value = getFieldValueByName(filedName, object);
            if (value != null) {
                urlKeyValue.append("&" + filedName + "=" + getFieldValueByName(filedName, object).toString());
            }
        }
        String ukv = urlKeyValue.toString();
        return ukv.substring(1);
    }

    /**
     * url键值对
     *
     * @param map
     * @return
     */
    public  String getUrlkeyValuePair(Map<String,Object> map) {
        String[] filedNames = map.keySet().toArray(new String[0]);
        Arrays.sort(filedNames);
        StringBuffer urlKeyValue = new StringBuffer();
        for (String filedName : filedNames) {
            Object value = map.get(filedName);
            if (value != null) {
                urlKeyValue.append("&" + filedName + "=" + map.get(filedName).toString());
            }
        }
        String ukv = urlKeyValue.toString();
        return ukv.substring(1);
    }

    /**
     * 获取属性名数组
     *
     * @param object
     * @return
     */
    private  String[] getFiledNames(Object object) {
        Field[] fields = object.getClass().getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) {
//            System.out.println(fields[i].getType());
            fieldNames[i] = fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * 获取属性值
     *
     * @param fieldName
     * @param object
     * @return
     */
    private  Object getFieldValueByName(String fieldName, Object object) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = object.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(object, new Object[]{});
            return value;
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
                | SecurityException e) {

            return null;
        }
    }






    public static void main(String[] args) {
        /*
        UnifiedOrder unifiedOrder = new UnifiedOrder();
        String sign = SignUtil.getSign(unifiedOrder);
        System.out.println("sign" + sign);
        String[] staArr = {"b2e", "f1w", "dfw", "aax", "2e2", "6q4", "3f5", "2t5"};
        for (int i = 0; i < staArr.length; i++) {
            Arrays.sort(staArr);
            System.out.println(staArr[i]);
        }
        */
        Map<String,Object> map = new ConcurrentHashMap<>();
        map.put("appId","wx723d90bd52ea1c84");
        map.put("timeStamp","1642869541");
        map.put("nonceStr","csQosfgA8GJnT38Q0gfP3QL4ubS6ZrNv");
        map.put("package","prepay_id=wx23003902118326a2ed5abab8d4d4f00000");
        map.put("signType","MD5");
        //map.put("paySign","70EA570631E4BB79628FBCA90534C63FF7FADD89");
        SignUtil signUtil = new SignUtil();
        String sign = signUtil.getSign(map);
        System.out.println(sign);
    }
}
